package com.genscript.ms.b.core.aop.aspect;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

@Aspect
@Component
@Order(-5)
public class HttpAspect {
    private Logger logger = LoggerFactory.getLogger("httpRequestLogger");

    @Autowired
    private ObjectMapper objectMapper;

    private ThreadLocal<Long> startTime = new ThreadLocal<>();

    @Pointcut("execution(* com.genscript.*..*Ctrl.*(..))")
    public void controllerAspect() {
    }

    @Before("controllerAspect()")
    public void doBefore(JoinPoint joinPoint) {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();

        logger.info("------------------------------------------------------------------------");
        logger.info("{}：[{}] [{}] {}",
                request.getMethod(),
                LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")),
                "IP",
                request.getRequestURL().toString());

        String requestBody = "{}";
        if (MediaType.APPLICATION_JSON_VALUE.equals(request.getContentType()) || MediaType.APPLICATION_JSON_UTF8_VALUE.equals(request.getContentType())) {
            try {
                requestBody = objectMapper.writeValueAsString(joinPoint.getArgs());
            } catch (JsonProcessingException e) {
                logger.error(e.getMessage(), e);
            }
        } else {
            requestBody = "";
        }
        logger.info("参数：{}", requestBody);

        startTime.set(System.currentTimeMillis());
    }

    @After("controllerAspect()")
    public void doAfter() {
        logger.info("耗时：{}ms", System.currentTimeMillis() - startTime.get());
        startTime.remove();
    }

    @Around("controllerAspect()")
    public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
        logger.debug("[Aspect] around advise 1");
        Object ob = pjp.proceed();
        logger.debug("[Aspect] around advise 2");
        return ob;
    }

    @AfterReturning(returning = "object", pointcut = "controllerAspect()")
    public void doAfterReturning(Object object) {
        try {
            logger.info("响应：{}", objectMapper.writeValueAsString(object));
        } catch (JsonProcessingException e) {
            logger.error(e.getMessage(), e);
        }
    }

    @AfterThrowing(throwing = "ex", pointcut = "controllerAspect()")
    public void doAfterThrowing(Exception ex) {
        logger.info("异常：{}", ex.getMessage());
    }
}
